# Plugin API

In the previous section, we introduced the basic structure of the plugin. In this section, we will introduce the API of the plugin to help you understand the abilities of the plugin in more detail.

### globalStyles

- **Type**：`string`

It is used to add a global style, and the absolute path of a style file is passed in, and the usage is as follows:

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';
import path from 'path';

export function pluginForDoc(): RspressPlugin {
  // style path
  const stylePath = path.join(__dirname, 'some-style.css');
  return {
    // plugin name
    name: 'plugin-name',
    globalStyles: path.join(__dirname, 'global.css'),
  };
}
```

For example, if you want to modify the theme color, you can do so by adding a global style:

```css title="global.css"
:root {
  --rp-c-brand: #ffa500;
  --rp-c-brand-dark: #ffa500;
  --rp-c-brand-darker: #c26c1d;
  --rp-c-brand-light: #f2a65a;
  --rp-c-brand-lighter: #f2a65a;
}
```

### globalUIComponents

- **Type**：`(string | [string, object])[]`

It is used to add global components, passing in an array, each item in the array is the absolute path of a component, the usage is as follows:

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(): RspressPlugin {
  // component path
  const componentPath = path.join(__dirname, 'foo.tsx');
  return {
    // plugin name
    name: 'plugin-comp',
    // Path to global components
    globalUIComponents: [componentPath],
  };
}
```

The item of `globalUIComponents` can be a string, which is the path of the component file, or an array, the first item is the path of the component file, and the second item is the component props, for example:

```ts title="rspress.config.ts"
import { defineConfig } from '@rspress/core';
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(): RspressPlugin {
  // component path
  const componentPath = path.join(__dirname, 'foo.tsx');
  return {
    // plugin name
    name: 'plugin-comp',
    globalUIComponents: [
      [
        path.join(__dirname, 'components', 'MyComponent.tsx'),
        {
          foo: 'bar',
        },
      ],
    ],
  };
}
```

import GlobalUIComponents from '../../fragments/global-ui-components.mdx';

<GlobalUIComponents />

### builderConfig

- **Type**：`RsbuildConfig`

Rspress uses [Rsbuild](https://github.com/web-infra-dev/rsbuild) as the build tool. Rsbuild can be configured through `builderConfig`. For specific configuration options, please refer to [Rsbuild(https://rsbuild.rs/config/).

> Of course, if you want to configure Rspack directly, you can also configure it through `builderConfig.tools.rspack`.

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(slug: string): RspressPlugin {
  return {
    name: 'plugin-name',
    // Global variable definitions for build phase
    builderConfig: {
      source: {
        define: {
          SLUG: JSON.stringify(slug),
        },
      },
      tools: {
        rspack(options) {
          // Modify rspack config
        },
      },
    },
  };
}
```

> See [Build Config](/api/config/config-build) for more details.

### config

- **Type**：`(config: DocConfig, utils: ConfigUtils) => DocConfig | Promise<DocConfig>`

The type of `ConfigUtils` is as follows:

```ts
interface ConfigUtils {
  addPlugin: (plugin: RspressPlugin) => void;
  removePlugin: (pluginName: string) => void;
}
```

It is used to modify/extend the configuration of Rspress itself. For example, if you want to modify the title of the document, you can do it through `config`:

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(): RspressPlugin {
  return {
    // Plugin name
    name: 'plugin-name',
    // Extend the config of the Rspress itself
    config(config) {
      return {
        ...config,
        title: 'New Document Title',
      };
    },
  };
}
```

If it involves adding and removing a plugin, you need to implement it through `addPlugin` and `removePlugin`:

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(): RspressPlugin {
  return {
    // Plugin name
    name: 'plugin-name',
    // Extend the config of Rspress itself
    config(config, utils) {
      // Add a plugin
      utils.addPlugin({
        name: 'plugin-name',
        // ... other config of the plugin
      });
      // Remove a plugin, pass in the name of the plugin
      utils.removePlugin('plugin-name');
      return config;
    },
  };
}
```

### beforeBuild/afterBuild

- **Type**：`(config: DocConfig, isProd: boolean) => void | Promise<void>`

It is used to perform some operations before/after the document is built. The first parameter is the config of the document, and the second parameter is whether it is currently a production environment. The usage is as follows:

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(): RspressPlugin {
  return {
    name: 'plugin-name',
    // Hook to execute before build
    async beforeBuild(config, isProd) {
      // Do something here
    },
    // Hook to execute after build
    async afterBuild(config, isProd) {
      // Do something here
    },
  };
}
```

:::tip
When the `beforeBuild` hook is executed, the `config` plugins of all plugins have been processed, so the config parameter already represents the final document configuration.
:::

### markdown

- **Type**：`{ remarkPlugins?: Plugin[]; rehypePlugins?: Plugin[] }`

It is used to extend the compilation ability of Markdown/MDX. If you want to add custom remark/rehype plugins or MDX globalComponents, you can use `markdown` options to achieve:

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(): RspressPlugin {
  return {
    name: 'plugin-name',
    markdown: {
      // Use js version compiler to support plugins
      mdxRs: false,
      remarkPlugins: [
        // Add custom remark plugin
      ],
      rehypePlugins: [
        // Add custom rehype plugin
      ],
      globalComponents: [
        // Register global components for MDX
      ],
    },
  };
}
```

### extendPageData

- Type: `(pageData: PageData) => void | Promise<void>`

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(): RspressPlugin {
  return {
    name: 'plugin-name',
    // Extend the page data
    extendPageData(pageData, isProd) {
      // You can add or modify properties on the pageData object
      pageData.a = 1;
    },
  };
}
```

After extending the page data, you can access the page data through the `usePageData` hook in the theme.

```tsx
import { usePageData } from '@rspress/core/runtime';

export function MyComponent() {
  const { page } = usePageData();
  // page.a === 1
  return <div>{page.a}</div>;
}
```

### addPages

- Type: `(config: UserConfig) => AdditionalPage[] | Promise<AdditionalPage[]>`

The `config` parameter is the `doc` config of `rspress.config.ts`, and the `AdditionalPage` type is defined as follows:

```tsx
interface AdditionalPage {
  routePath: string;
  filepath?: string;
  content?: string;
}
```

Used to add additional pages, you can return an array in the `addPages` function, each item in the array is a page config, you can specify the route of the page through `routePath`, through `filepath` or `content` to specify the content of the page. For example:

```tsx
import path from 'path';
import type { RspressPlugin } from '@rspress/core';

export function docPluginDemo(): RspressPlugin {
  return {
    name: 'add-pages',
    addPages(config, isProd) {
      return [
        //  Support the absolute path of the real file (filepath), which will read the content of md(x) in the disk
        {
          routePath: '/filepath-route',
          filepath: path.join(__dirname, 'blog', 'index.md'),
        },
        //  Support to directly pass in the content of md(x) through the content parameter
        {
          routePath: '/content-route',
          content: '# Demo2',
        },
      ];
    },
  };
}
```

`addPages` accepts two parameters, `config` is the config of the current document site, `isProd` indicates whether it is a production environment.

### routeGenerated

- **Type**：`(routeMeta: RouteMeta[]) => void | Promise<void>`

In this hook, you can get all the route meta information. The structure of each route meta information is as follows

```ts
export interface RouteMeta {
  // route path
  routePath: string;
  // file absolute path
  absolutePath: string;
  // The page name, as part of the chunk filename
  pageName: string;
  // language of current route
  lang: string;
}
```

例子:

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(): RspressPlugin {
  return {
    // plugin name
    name: 'plugin-routes',
    // Hook to execute after route generated
    async routeGenerated(routes, isProd) {
      // Do something here
    },
  };
}
```

### addRuntimeModules

- **Type**: `(config: UserConfig, isProd: boolean) => Record<string, string> | Promise<Record<string, string>>;`

Used to add additional runtime modules. For example, if you want to use some compile-time information in the document, you can achieve this through `addRuntimeModules`:

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(): RspressPlugin {
  return {
    // Plugin name
    name: 'plugin-name',
    // Add additional runtime modules
    async addRuntimeModules(config, isProd) {
      const fetchSomeData = async () => {
        // Mock asynchronous request
        return { a: 1 };
      };
      const data = await fetchSomeData();
      return {
        'virtual-foo': `export default ${JSON.stringify(data)}`,
      };
    },
  };
}
```

In this way, you can use the `virtual-foo` module in the runtime component:

```jsx
import myData from 'virtual-foo';

export function MyComponent() {
  return <div>{myData.a}</div>;
}
```

:::tip TIP

This hook is executed after the `routeGenerated` hook.

:::

### i18nSource

- **Type**: `(source: Record<string, Record<string, string>>) => Record<string, Record<string, string>> | Promise<Record<string, Record<string, string>>>`

Used to add or modify internationalization (i18n) text data. You can use this hook to extend or modify the theme's i18n text.

The `source` parameter is an object with the following structure:

```ts
{
  [textKey: string]: {
    [locale: string]: string;
  }
}
```

Where the first-level `textKey` is the text key name, the second-level `locale` is the language code (e.g., `zh`, `en`), and the value is the translated text for the corresponding language.

Usage example:

```tsx title="plugin.ts"
import type { RspressPlugin } from '@rspress/core';

export function pluginForDoc(): RspressPlugin {
  return {
    // Plugin name
    name: 'plugin-name',
    // Add or modify i18n text
    i18nSource(source) {
      // Add new text
      return {
        ...source,
        customKey: {
          zh: '自定义文案',
          en: 'Custom Text',
        },
        anotherKey: {
          zh: '另一个文案',
          en: 'Another Text',
        },
      };
    },
  };
}
```

If your plugin provides runtime components at the same time, you can use these texts via the `useI18n` hook:

```tsx
import { useI18n } from '@rspress/core/runtime';

export function MyComponent() {
  const t = useI18n();
  return <div>{t('customKey')}</div>;
}
```
